# coding:utf-8

import math
import conf
from .geo_classes import Node, Region
from shapely.geometry import Polygon

earthR = 6378137.0


def circle2tiles(circle, china_convert):
    left_up_x, left_up_y = wgs2tile(circle.left_up_corner.lat, circle.left_up_corner.lng, conf.ZOOM_LEVEL)
    right_down_x, right_down_y = wgs2tile(circle.right_down_corner.lat, circle.right_down_corner.lng, conf.ZOOM_LEVEL)
    output_tiles = []
    for x in range(left_up_x, right_down_x + 1):
        for y in range(left_up_y, right_down_y + 1):
            tile_center_node = Node(*tile2wgs(x + 0.5, y + 0.5, conf.ZOOM_LEVEL))
            is_in = tile_center_node.in_(circle)
            if is_in:
                # print(x, y, True)
                if china_convert is False:
                    output_tiles.append((x, y, conf.ZOOM_LEVEL))
                else:
                    new_x, new_y = wgstile2gcjtile(x, y, conf.ZOOM_LEVEL)
                    output_tiles.append((new_x, new_y, conf.ZOOM_LEVEL))
    return output_tiles


def way2tiles(way, china_convert):
    left_up_x, left_up_y = wgs2tile(way.left_up_corner.lat, way.left_up_corner.lng, conf.ZOOM_LEVEL)
    right_down_x, right_down_y = wgs2tile(way.right_down_corner.lat, way.right_down_corner.lng, conf.ZOOM_LEVEL)
    output_tiles = []
    way_polygon = Polygon([(node.lat, node.lng) for node in way.nodes])
    # print(left_up_x, right_down_x, left_up_y, right_down_y)
    for x in range(left_up_x, right_down_x + 1):
        for y in range(left_up_y, right_down_y + 1):
            # print(x, y)
            tile_left_up = Node(*tile2wgs(x, y, conf.ZOOM_LEVEL))
            tile_right_down = Node(*tile2wgs(x + 1, y + 1, conf.ZOOM_LEVEL))
            tile_region = Region(tile_left_up, tile_right_down)
            # print(str(tile_left_up), str(tile_right_down))
            if conf.IN_TYPE == 'center':
                is_in = tile_region.center_in(way)
            elif conf.IN_TYPE == '4_nodes':
                is_in = tile_region.in_(way)
            elif conf.IN_TYPE == 'area':
                is_in = tile_region.area_fit_with(way_polygon)
            else:
                raise NotImplementedError
            if is_in:
                # print(x, y, True)
                if china_convert is False:
                    output_tiles.append((x, y, conf.ZOOM_LEVEL))
                else:
                    new_x, new_y = wgstile2gcjtile(x, y, conf.ZOOM_LEVEL)
                    output_tiles.append((new_x, new_y, conf.ZOOM_LEVEL))
    return output_tiles


def wgs2tile(lat_deg, lng_deg, zoom):
    lat_rad = math.radians(lat_deg)
    n = 2.0 ** zoom
    xtile = int((lng_deg + 180.0) / 360.0 * n)
    ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
    return (xtile, ytile)


def wgstile2gcjtile(x, y, zoom):
    """x, y是左上角位置"""
    x = x + 0.5
    y = y + 0.5
    lat, lng = tile2wgs(x, y, zoom)
    gcj_lat, gcj_lng = wgs2gcj(lat, lng)
    return wgs2tile(gcj_lat, gcj_lng, zoom)


def tile2wgs(xtile, ytile, zoom):
    n = 2.0 ** zoom
    lng_deg = xtile / n * 360.0 - 180.0
    lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
    lat_deg = math.degrees(lat_rad)
    return (lat_deg, lng_deg)


def outOfChina(lat, lng):
    return not (72.004 <= lng <= 137.8347 and 0.8293 <= lat <= 55.8271)


def transform(x, y):
    xy = x * y
    absX = math.sqrt(abs(x))
    xPi = x * math.pi
    yPi = y * math.pi
    d = 20.0 * math.sin(6.0 * xPi) + 20.0 * math.sin(2.0 * xPi)

    lat = d
    lng = d

    lat += 20.0 * math.sin(yPi) + 40.0 * math.sin(yPi / 3.0)
    lng += 20.0 * math.sin(xPi) + 40.0 * math.sin(xPi / 3.0)

    lat += 160.0 * math.sin(yPi / 12.0) + 320 * math.sin(yPi / 30.0)
    lng += 150.0 * math.sin(xPi / 12.0) + 300.0 * math.sin(xPi / 30.0)

    lat *= 2.0 / 3.0
    lng *= 2.0 / 3.0

    lat += -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * xy + 0.2 * absX
    lng += 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * xy + 0.1 * absX

    return lat, lng


def delta(lat, lng):
    ee = 0.00669342162296594323
    dLat, dLng = transform(lng - 105.0, lat - 35.0)
    radLat = lat / 180.0 * math.pi
    magic = math.sin(radLat)
    magic = 1 - ee * magic * magic
    sqrtMagic = math.sqrt(magic)
    dLat = (dLat * 180.0) / ((earthR * (1 - ee)) / (magic * sqrtMagic) * math.pi)
    dLng = (dLng * 180.0) / (earthR / sqrtMagic * math.cos(radLat) * math.pi)

    return dLat, dLng


def wgs2gcj(wgsLat, wgsLng):
    if outOfChina(wgsLat, wgsLng):
        return wgsLat, wgsLng
    else:
        dlat, dlng = delta(wgsLat, wgsLng)
        return wgsLat + dlat, wgsLng + dlng
